package com.ruoyi.ring.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.MealTypeEnums;
import com.ruoyi.common.enums.PlanStatusEnums;
import com.ruoyi.common.enums.SexEnums;
import com.ruoyi.common.enums.TimeUnitEnums;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.Builder;
import com.ruoyi.ring.domain.*;
import com.ruoyi.ring.domain.dto.GeneralSecondDTO;
import com.ruoyi.ring.domain.vo.*;
import com.ruoyi.ring.mapper.RingExerciseDetailMapper;
import com.ruoyi.ring.mapper.RingHealthPlanMapper;
import com.ruoyi.ring.mapper.RingSportDetailMapper;
import com.ruoyi.ring.mapper.UserFoodInfoMapper;
import com.ruoyi.ring.service.IFoodInfoSecondService;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class FoodInfoSecondServiceImpl implements IFoodInfoSecondService {
    @Resource
    private UserFoodInfoMapper userFoodInfoMapper;
    @Resource
    private RingHealthPlanMapper healthPlanMapper;
    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private RingExerciseDetailMapper exerciseDetailMapper;
    @Resource
    private RingSportDetailMapper sportDetailMapper;
    @Override
    public List<CalendarResultVO> queryCalendarList(GeneralSecondDTO secondDTO) {
        List<UserFoodInfo> userFoodInfos = userFoodInfoMapper.selectUserFoodInfoList(Builder.of(UserFoodInfo::new).with(UserFoodInfo::setUserId,SecurityUtils.getUserId()).build());
        List<CalendarResultVO> resultVOS = new ArrayList<>();
        userFoodInfos.forEach(u ->{
            CalendarResultVO resultVO = new CalendarResultVO();
            resultVO.setDailyValue(DateUtils.dateTime(DateUtils.YYYY_MM_DD, DateUtils.dateTime(u.getRecordDate())));
            resultVOS.add(resultVO);
        });
        ZoneId zoneId = ZoneId.systemDefault();
        List<CalendarResultVO> list = resultVOS.stream()
                .collect(Collectors.toMap(
                        vo -> vo.getDailyValue().toInstant().atZone(zoneId).toLocalDate(),
                        Function.identity(),
                        (existing, replacement) -> existing
                ))
                .values()
                .stream()
                // 使用Comparator.comparing指定按日期正序
                .sorted(Comparator.comparing(vo -> vo.getDailyValue().toInstant().atZone(zoneId).toLocalDate()))
                .collect(Collectors.toList());
        return list;
    }
    @Override
    public FoodInfoVO queryFoodInfo(GeneralSecondDTO secondDTO) {
        secondDTO.setUserId(SecurityUtils.getUserId());
        FoodInfoVO foodInfoVO = new FoodInfoVO();
        List<FoodInfoVO.ChartVO> chartVOList = new ArrayList<>();
        List<GeneralGroupVO> groupVOList = userFoodInfoMapper.queryFoodInfoList(secondDTO);
        RingHealthPlan healthPlan = healthPlanMapper.selectOneRingHealthPlan(Builder.of(RingHealthPlan::new).
                with(RingHealthPlan::setPlanStatus, PlanStatusEnums.IN_PROGRESS.getCode()).
                with(RingHealthPlan::setUserId, SecurityUtils.getUserId()).build());
        if(healthPlan != null){
            foodInfoVO.setIntakeCalories(healthPlan.getCalorie());
        }
        List<FoodInfoListVO> listVOList = new ArrayList<>();
        for (GeneralGroupVO group : groupVOList) {
            if(!TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())){
                foodInfoVO.setDateStart(group.getDateStart()+ "，" + DateUtils.getChineseWeekday(group.getDateStart()));
                foodInfoVO.setDateEnd(group.getDateEnd()+ "，" + DateUtils.getChineseWeekday(group.getDateEnd()));
            }
            foodInfoVO.setRecordDate(group.getDailyValue());
            foodInfoVO.setWeekName(group.getWeekName());
            String groupData = group.getGroupData(); // 包含多条记录的JSON数组
            // 解析JSON数组为具体的实体类（假设有子实体类 BloodOxygenDetail）
            if(groupData != null){
                listVOList.addAll(queryFoodInfoList(groupData));
            }
        }
        int calories = 0;
        if(TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())){
            listVOList = listVOList.stream().sorted(Comparator.comparingLong(FoodInfoListVO::getId)).collect(Collectors.toList());
            calories = listVOList.stream().mapToInt(d -> Convert.toInt(d.getCalories())).sum();
            for(FoodInfoListVO listVO : listVOList){
                FoodInfoVO.ChartVO info = new FoodInfoVO.ChartVO();
                String key = "";
                int value = 0;
                if(MealTypeEnums.BREAKFAST.getCode().equals(listVO.getMealType())){
                    key = MealTypeEnums.BREAKFAST.getInfo();
                    value = Convert.toInt(listVO.getCalories());
                }else if(MealTypeEnums.LUNCH.getCode().equals(listVO.getMealType())){
                    key = MealTypeEnums.LUNCH.getInfo();
                    value = Convert.toInt(listVO.getCalories());
                }else if(MealTypeEnums.DINNER.getCode().equals(listVO.getMealType())){
                    key = MealTypeEnums.DINNER.getInfo();
                    value = Convert.toInt(listVO.getCalories());
                }else if (MealTypeEnums.OTHER.getCode().equals(listVO.getMealType())){
                    key = MealTypeEnums.DINNER.getInfo();
                    value = Convert.toInt(listVO.getCalories());
                }else {
                    continue;
                }
                info.setKey(key);
                info.setValue(value);
                info.setTimeLabel(DateUtils.convertDateTimeToHHMM(listVO.getRecordTime()));
                chartVOList.add(info);
            }
        }else if(TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType())){
            List<Date> dateList = DateUtils.getWeekDatesLegacy(secondDTO.getRecordDate());
            calories = groupVOList.size() > 0 ? listVOList.stream().mapToInt(d -> Convert.toInt(d.getCalories())).sum() / groupVOList.size() : 0;
            for(Date date : dateList){
                FoodInfoVO.ChartVO info = new FoodInfoVO.ChartVO();
                String key = DateUtils.convertDateToMMdd(date);
                int value = Convert.toInt(listVOList.stream().filter(num -> num.getRecordDate().getTime() == date.getTime()).mapToInt(d -> Convert.toInt(d.getCalories())).sum());
                info.setKey(key);
                info.setValue(value);
                chartVOList.add(info);
            }
        }else {
            List<Date> dateList = DateUtils.getMonthDatesLegacy(secondDTO.getRecordDate());
            calories = groupVOList.size() > 0 ? listVOList.stream().mapToInt(d -> Convert.toInt(d.getCalories())).sum() / groupVOList.size() : 0;
            for(Date date : dateList){
                FoodInfoVO.ChartVO info = new FoodInfoVO.ChartVO();
                String key = DateUtils.queryMonthday(date);
                int value = Convert.toInt(listVOList.stream().filter(num -> num.getRecordDate().getTime() == date.getTime()).mapToInt(d -> Convert.toInt(d.getCalories())).sum());
                info.setKey(key);
                info.setValue(value);
                chartVOList.add(info);
            }
        }
        foodInfoVO.setCalories(calories);
        foodInfoVO.setChartVOList(chartVOList);
        return foodInfoVO;
    }
    @Override
    public EnergyBalanceVO queryEnergyBalance(GeneralSecondDTO secondDTO) {
        EnergyBalanceVO energyBalanceVO = new EnergyBalanceVO();
        long userId;
        if(secondDTO.getUserId() != null){
            userId = secondDTO.getUserId();
        }else {
            userId = SecurityUtils.getUserId();
        }
        secondDTO.setUserId(userId);
        SysUser sysUser = sysUserMapper.queryUserHealthQuestion(secondDTO.getUserId());
        String sex = sysUser.getSex();
        int height = sysUser.getHeight() != null ? sysUser.getHeight() : 0;
        int age = sysUser.getBirthday() != null ? DateUtils.calculateAge(sysUser.getBirthday()) : 0;
        double weight = sysUser.getWeight() != null ? sysUser.getWeight() : 0;
        //男性：BMR = 10 × 体重(kg) + 6.25 × 身高(cm) - 5 × 年龄(岁) + 5
        //女性：BMR = 10 × 体重(kg) + 6.25 × 身高(cm) - 5 × 年龄(岁) - 161
        int basalMetabolism = 0;//基础代谢
        if(SexEnums.MALE.getCode().equals(sex)){//男
            basalMetabolism = Convert.toInt(10 * weight + 6.25 * height - 5 * age + 5);
        }else if (SexEnums.FEMALE.getCode().equals(sex)){//女
            basalMetabolism = Convert.toInt(10 * weight + 6.25 * height - 5 * age - 161);
        }

        List<UserFoodInfo>  userFoodInfos = userFoodInfoMapper.queryUserFoodList(secondDTO);
        List<RingExerciseDetail> exerciseDetails = exerciseDetailMapper.querySportHeartRate(secondDTO);
        List<RingSportDetail>  sportDetails = sportDetailMapper.queryRingSportDetailList(secondDTO);
        if(userFoodInfos != null && (exerciseDetails != null || sportDetails != null)){
            energyBalanceVO = queryEnergyBalanceVO(basalMetabolism, secondDTO.getType(), userFoodInfos, exerciseDetails, sportDetails);
        }
        return energyBalanceVO;
    }

    public EnergyBalanceVO queryEnergyBalanceVO(int basalMetabolism, String type, List<UserFoodInfo>  userFoodInfos, List<RingExerciseDetail> exerciseDetails, List<RingSportDetail>  sportDetails){
        EnergyBalanceVO energyBalanceVO = new EnergyBalanceVO();
        //明确每种营养素每克提供的热量步骤-:蛋白质每克蛋白质提供 4千卡热量。
        //碳水化合物:每克碳水化合物提供 4 千卡热量。
        //脂肪:每克脂肪提供 9千卡热量。
        if (TimeUnitEnums.DAY.getCode().equals(type)) {
            // 蛋白质(g)
            int protein = userFoodInfos.stream().mapToInt(f -> Math.toIntExact(Convert.toInt(f.getProtein()))).sum();
            // 碳水化合物(g)
            int carbohydrate = userFoodInfos.stream().mapToInt(f -> Math.toIntExact(Convert.toInt(f.getCarbohydrate()))).sum();
            // 脂肪(g)
            int fat = userFoodInfos.stream().mapToInt(f -> Math.toIntExact(Convert.toInt(f.getFat()))).sum();

            int proteinKcal = protein * 4;
            int carbohydrateKcal = carbohydrate * 4;
            int fatKcal = fat * 9;
            int totalFoodKcal = proteinKcal + carbohydrateKcal + fatKcal;

            energyBalanceVO.setTotalFoodKcal(totalFoodKcal);
            energyBalanceVO.setProteinKcal(proteinKcal);
            energyBalanceVO.setCarbohydrateKcal(carbohydrateKcal);
            energyBalanceVO.setFatKcal(fatKcal);

            // 运动消耗卡路里
            int sportKcal = exerciseDetails.stream().map(e -> e.getCalories() != null ? Math.toIntExact(e.getCalories()) : 0).mapToInt(Integer::intValue).sum();
            // 日常消耗卡路里
            int dailyKcal = sportDetails.stream().map(s -> s.getCalories() != null ? Math.toIntExact(s.getCalories()) : 0).mapToInt(Integer::intValue).sum();
            // 活动总消耗卡路里
            int totalExerciseKcal = basalMetabolism + sportKcal + dailyKcal;

            energyBalanceVO.setBasalMetabolism(basalMetabolism);
            energyBalanceVO.setSportKcal(sportKcal);
            energyBalanceVO.setDailyKcal(dailyKcal);
            energyBalanceVO.setTotalExerciseKcal(totalExerciseKcal);

            energyBalanceVO.setEnergyBalance( totalFoodKcal - totalExerciseKcal);

        }else {
            ZoneId zoneId = ZoneId.systemDefault();
            int foodDayCount = Convert.toInt(userFoodInfos.stream()
                    .map(foodInfo -> {
                        Date date = foodInfo.getRecordDate();
                        return date.toInstant().atZone(zoneId).toLocalDate();
                    }).distinct().count());
            // 蛋白质(g)
            int protein = foodDayCount > 0 ? userFoodInfos.stream().mapToInt(f -> Math.toIntExact(Convert.toInt(f.getProtein()))).sum() / foodDayCount : 0;
            // 碳水化合物(g)
            int carbohydrate = foodDayCount > 0 ? userFoodInfos.stream().mapToInt(f -> Math.toIntExact(Convert.toInt(f.getCarbohydrate()))).sum() / foodDayCount : 0;
            // 脂肪(g)
            int fat = foodDayCount > 0 ? userFoodInfos.stream().mapToInt(f -> Math.toIntExact(Convert.toInt(f.getFat()))).sum() / foodDayCount : 0;

            int proteinKcal = protein * 4;
            int carbohydrateKcal = carbohydrate * 4;
            int fatKcal = fat * 9;
            int totalFoodKcal = proteinKcal + carbohydrateKcal + fatKcal;

            energyBalanceVO.setTotalFoodKcal(totalFoodKcal);
            energyBalanceVO.setProteinKcal(proteinKcal);
            energyBalanceVO.setCarbohydrateKcal(carbohydrateKcal);
            energyBalanceVO.setFatKcal(fatKcal);

            int exerDayCount = Convert.toInt(exerciseDetails.stream()
                    .map(exer -> {
                        Date date = exer.getRecordDate();
                        return date.toInstant().atZone(zoneId).toLocalDate();
                    }).distinct().count());
            // 运动消耗卡路里
            int sportKcal = exerDayCount > 0 ? exerciseDetails.stream().mapToInt(e -> Math.toIntExact(e.getCalories())).sum() / exerDayCount : 0;

            int sportDayCount = Convert.toInt(sportDetails.stream()
                    .map(exer -> {
                        Date date = exer.getHistoryDay();
                        return date.toInstant().atZone(zoneId).toLocalDate();
                    }).distinct().count());

            // 日常消耗卡路里
            int dailyKcal = sportDayCount > 0 ? sportDetails.stream().mapToInt(s ->  Math.toIntExact(s.getCalories())).sum() / sportDayCount : 0;
            // 活动总消耗卡路里
            int totalExerciseKcal = basalMetabolism + sportKcal + dailyKcal;
            energyBalanceVO.setBasalMetabolism(basalMetabolism);
            energyBalanceVO.setSportKcal(sportKcal);
            energyBalanceVO.setDailyKcal(dailyKcal);
            energyBalanceVO.setTotalExerciseKcal(totalExerciseKcal);

            energyBalanceVO.setEnergyBalance( totalFoodKcal - totalExerciseKcal);

        }

        return energyBalanceVO;
    }

    @Override
    public AjaxResult queryFoodList(GeneralSecondDTO secondDTO) {
        FoodDayListVO dayListVO = new FoodDayListVO();

        FoodWeekListVO weekListVO = new FoodWeekListVO();
        List<FoodWeekListVO.FoodDayVO> foodWeekVOS = new ArrayList<>();

        FoodMonthListVO monthListVO = new FoodMonthListVO();
        List<FoodMonthListVO.FoodDayVO> foodMonthVOS = new ArrayList<>();

        secondDTO.setUserId(SecurityUtils.getUserId());
        List<GeneralGroupVO> groupVOList = userFoodInfoMapper.queryFoodInfoList(secondDTO);
        String dateStart = "";
        String dateEnd = "";
        String recordDate = "";
        String weekName = "";
        for (GeneralGroupVO group : groupVOList) {
            List<FoodInfoListVO> listVOList = new ArrayList<>();
            if (!TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())) {
                dateStart = group.getDateStart() + "，" + DateUtils.getChineseWeekday(group.getDateStart());
                dateEnd = group.getDateEnd() + "，" + DateUtils.getChineseWeekday(group.getDateEnd());
            }
            recordDate = group.getDailyValue();
            weekName = group.getWeekName();
            String groupData = group.getGroupData(); // 包含多条记录的JSON数组
            // 解析JSON数组为具体的实体类（假设有子实体类 BloodOxygenDetail）
            if (groupData != null) {
                listVOList.addAll(queryFoodInfoList(groupData));
            }
            listVOList = listVOList.stream().sorted(Comparator.comparingLong(FoodInfoListVO::getId)).collect(Collectors.toList());
            if (TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())) {
                List<FoodDayListVO.FoodVO> foodVOS = new ArrayList<>();
                dayListVO.setRecordDate(recordDate);
                dayListVO.setWeekName(weekName);
                for (FoodInfoListVO vo : listVOList) {
                    foodVOS.add(queryFoodDayList(vo));
                }
                dayListVO.setFoodVOS(foodVOS);
            } else if (TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType())) {
                weekListVO.setDateStart(dateStart);
                weekListVO.setDateEnd(dateEnd);

                FoodWeekListVO.FoodDayVO foodWeekVO = new FoodWeekListVO.FoodDayVO();
                foodWeekVO.setRecordDate(recordDate);
                foodWeekVO.setWeekName(weekName);
                List<FoodWeekListVO.FoodDayVO.FoodVO> foodVOS = new ArrayList<>();
                for (FoodInfoListVO vo : listVOList) {
                    foodVOS.add(queryFoodWeekList(vo));
                }
                foodWeekVO.setFoodVOS(foodVOS);
                foodWeekVOS.add(foodWeekVO);
                weekListVO.setFoodDayVOS(foodWeekVOS);
            } else if (TimeUnitEnums.MONTH.getCode().equals(secondDTO.getType())) {
                monthListVO.setDateStart(dateStart);
                monthListVO.setDateEnd(dateEnd);
                FoodMonthListVO.FoodDayVO foodMonthVO = new FoodMonthListVO.FoodDayVO();
                foodMonthVO.setRecordDate(recordDate);
                foodMonthVO.setWeekName(weekName);
                List<FoodMonthListVO.FoodDayVO.FoodVO> foodVOS = new ArrayList<>();
                for (FoodInfoListVO vo : listVOList) {
                    foodVOS.add(queryFoodMonthList(vo));
                }
                foodMonthVO.setFoodVOS(foodVOS);
                foodMonthVOS.add(foodMonthVO);
                monthListVO.setFoodDayVOS(foodMonthVOS);
            }
        }
        if(TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())){
            return AjaxResult.success(dayListVO);
        }else if(TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType())){
            return AjaxResult.success(weekListVO);
        }else if(TimeUnitEnums.MONTH.getCode().equals(secondDTO.getType())){
            return AjaxResult.success(monthListVO);
        }
        return AjaxResult.success(null);
    }

    /** json字符串转换集合 */
    public List<FoodInfoListVO> queryFoodInfoList(String groupData){
        JSONArray jsonArray = JSONArray.parseArray(groupData);
        return jsonArray.toJavaList(FoodInfoListVO.class);
    }
    /** 匹配用餐类型 */
    public String queryMealType(String mealType){
        String result = "";
        if (MealTypeEnums.BREAKFAST.getCode().equals(mealType)) {
            result = MealTypeEnums.BREAKFAST.getInfo();
        } else if (MealTypeEnums.LUNCH.getCode().equals(mealType)) {
            result = MealTypeEnums.LUNCH.getInfo();
        } else if (MealTypeEnums.DINNER.getCode().equals(mealType)) {
            result = MealTypeEnums.DINNER.getInfo();
        } else if (MealTypeEnums.OTHER.getCode().equals(mealType)) {
            result = MealTypeEnums.DINNER.getInfo();
        }
        return result;
    }
    /** 组合天饮食信息 */
    public FoodDayListVO.FoodVO queryFoodDayList(FoodInfoListVO vo){
        FoodDayListVO.FoodVO foodVO = new FoodDayListVO.FoodVO();
        //食物名称
        foodVO.setFoodName(vo.getFoodName());
        //食物图片URL
        foodVO.setImageUrl(vo.getImageUrl());
        //记录时间
        foodVO.setRecordTime(vo.getRecordTime());
        //卡路里(千卡)
        foodVO.setCalories(Convert.toInt(vo.getCalories()));
        //蛋白质(g)
        foodVO.setProtein(Convert.toInt(vo.getProtein()));
        //碳水化合物(g)
        foodVO.setCarbohydrate(Convert.toInt(vo.getCarbohydrate()));
        //脂肪(g)
        foodVO.setFat(Convert.toInt(vo.getFat()));
        //用餐类型
        foodVO.setMealType(queryMealType(vo.getMealType()));
        return foodVO;
    }
    /** 组合周饮食信息 */
    public FoodWeekListVO.FoodDayVO.FoodVO queryFoodWeekList(FoodInfoListVO vo){
        FoodWeekListVO.FoodDayVO.FoodVO foodVO = new FoodWeekListVO.FoodDayVO.FoodVO();
        //食物名称
        foodVO.setFoodName(vo.getFoodName());
        //卡路里(千卡)
        foodVO.setCalories(Convert.toInt(vo.getCalories()));
        //蛋白质(g)
        foodVO.setProtein(Convert.toInt(vo.getProtein()));
        //碳水化合物(g)
        foodVO.setCarbohydrate(Convert.toInt(vo.getCarbohydrate()));
        //脂肪(g)
        foodVO.setFat(Convert.toInt(vo.getFat()));
        //用餐类型
        foodVO.setMealType(queryMealType(vo.getMealType()));
        return foodVO;
    }

    /** 组合月饮食信息 */
    public FoodMonthListVO.FoodDayVO.FoodVO queryFoodMonthList(FoodInfoListVO vo){
        FoodMonthListVO.FoodDayVO.FoodVO foodVO = new FoodMonthListVO.FoodDayVO.FoodVO();
        //食物名称
        foodVO.setFoodName(vo.getFoodName());
        //卡路里(千卡)
        foodVO.setCalories(Convert.toInt(vo.getCalories()));
        //用餐类型
        foodVO.setMealType(queryMealType(vo.getMealType()));
        return foodVO;
    }
}
